#
#    Copyright (C) 2016 Francisco Javier Parra <franparpe@openmailbox.org>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#

import matplotlib.pyplot as pyplot
from qtcam.core.sections.harmonic import HarmonicSection
from qtcam.core.sections.cycloidal import CicloidalSection
from qtcam.core.sections.polynomial5 import FifthDegreePolynomialSection
from qtcam.core.sections.polynomial7 import SeventhDegreePolynomialSection
from qtcam.core.sections.demiharmonic import DemiHarmonicSectionZeroVfinal, DemiHarmonicSectionZeroVinitial
from qtcam.core.sections.demicycloidal import DemiCicloidalSectionZeroVFinal, DemiCicloidalSectionZeroVInitial
from qtcam.core.sections.doubleharmonic import DoubleHarmonic
from qtcam.core.sections.modifiedsinusoidal import ModifiedSinusoidalSection
from qtcam.core.sections.modifiedtrapezoidal import ModifiedTrapezoidalSection
from qtcam.core.sections.bezier import BezierSection
from qtcam.core.sections.stop import StopSection
from dxfwrite import DXFEngine as dxf
import math
from qtcam.tools.check_continuity import checkContinuity
import numpy as np
#  No olvidar las divisiones por cero
#  Cuidado con la derivada de la aceleracion del polinomio
#  de quinto grado porque hay algo que no encaja
# Cuando se pueda, reunir todas los metodos de generación de levas en uno solo


class Cam(object):
    def __init__(self):
        self.sections = []
        self.rb = 0
        self.excentricity = 0
        self.beta = 0
        self.l1 = 0
        self.l2 = 0
        self.followerRadius = 0
        self.followerType = "plane"
        self.abcissaeValues = []
        self.precision = 0.1
        self.orDisplacement = []
        self.orVelocity = []
        self.orAcceleration = []
        self.orJerk = []
        self.restAbci = []

    def __len__(self):
        return len(self.sections)

    def add_cam_section(self, LowestPosition=0.0, HighestPosition=50.0,
                        StartAngle=100.0, EndAngle=200.0,
                        Precision=0.1, AngularVelocity=1.0,
                        sectionType="stop", continuity=2, vector="double detention"):
        """This method adds a CamSection to the list of sections

        Keyword Arguments:
        LowestPosition                    -- (default 0.0)
        HighestPosition                   -- (default 50.0)
        StartAngle       -- (default self.endPreviousAngle)
        EndAngle                          -- (default 200)
        Precision                         -- (default 0.1)
        AngularVelocity                   -- (default 20.0)
        """
        a = 0
        if sectionType == "harmonic":
            a = HarmonicSection(LowestPosition, HighestPosition, StartAngle,
                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "cicloidal":
            a = CicloidalSection(LowestPosition, HighestPosition, StartAngle,
                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "5polynomial":
            a = FifthDegreePolynomialSection(LowestPosition,
                                             HighestPosition, StartAngle,
                                             EndAngle, Precision, AngularVelocity)
        elif sectionType == "7polynomial":
            a = SeventhDegreePolynomialSection(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "demiharmonic_Vi":
            a = DemiHarmonicSectionZeroVinitial(LowestPosition, HighestPosition, StartAngle,
                                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "demiharmonic_Vf":
            a = DemiHarmonicSectionZeroVfinal(LowestPosition, HighestPosition, StartAngle,
                                              EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vf":
            a = DemiCicloidalSectionZeroVFinal(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vi":
            a = DemiCicloidalSectionZeroVInitial(LowestPosition, HighestPosition, StartAngle,
                                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "double_harmonic":
            a = DoubleHarmonic(LowestPosition, HighestPosition, StartAngle,
                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "modified_sinusoidal":
            a = ModifiedSinusoidalSection(LowestPosition, HighestPosition,
                                          StartAngle, EndAngle, Precision,
                                          AngularVelocity)
        elif sectionType == "modified_trapezoidal":
            a = ModifiedTrapezoidalSection(LowestPosition, HighestPosition,
                                           StartAngle, EndAngle, Precision,
                                           AngularVelocity)
        elif sectionType == "bezier":
            a = BezierSection(LowestPosition, HighestPosition,
                              StartAngle, EndAngle, Precision,
                              AngularVelocity, continuity, vector)

        elif sectionType == "stop":
            a = StopSection(StartAngle, EndAngle, LowestPosition,
                            AngularVelocity, Precision)

        else:  # Seguir aquí que algo pasa
            print("supported types: \n\nharmonic\ncicloidal\n5polynomial\n7polynomial\ndemiharmonic_Vi\ndemiharmonic_Vf")

        self.sections.append(a)
        # self.endPreviousAngle = a.EndAngle  # Atento

    def change_section_type(self, section=0, sectionType="harmonic"):
        """It changes the section type given the section number (being 0 the first one)
        and the new type which can be: harmonic, cicloidal, 5polynomial, 7polynomial

        Keyword Arguments:
        section     -- (default 0)
        sectionType -- (default "harmonic")
        """
        LowestPosition, HighestPosition, StartAngle, EndAngle, Precision, AngularVelocity = self.return_section_parameters(section)
        a = HarmonicSection(LowestPosition, HighestPosition, StartAngle,
                            EndAngle, Precision, AngularVelocity)

        if sectionType == "Harmonic":
            a = HarmonicSection(LowestPosition, HighestPosition, StartAngle,
                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "Cycloidal":
            a = CicloidalSection(LowestPosition, HighestPosition, StartAngle,
                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "5º degree polynomial":
            a = FifthDegreePolynomialSection(LowestPosition, HighestPosition,
                                             StartAngle, EndAngle, Precision,
                                             AngularVelocity)
        elif sectionType == "7º degree polynomial":
            a = SeventhDegreePolynomialSection(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "Demiharmonic Vi=0":
            a = DemiHarmonicSectionZeroVinitial(LowestPosition, HighestPosition, StartAngle,
                                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "Demiharmonic Vf=0":
            a = DemiHarmonicSectionZeroVfinal(LowestPosition, HighestPosition, StartAngle,
                                              EndAngle, Precision, AngularVelocity)
        elif sectionType == "Demicycloidal Vi=0":
            a = DemiCicloidalSectionZeroVInitial(LowestPosition, HighestPosition, StartAngle,
                                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "Demicycloidal Vf=0":
            a = DemiCicloidalSectionZeroVFinal(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)

        elif sectionType == "DoubleHarmonic":
            a = DoubleHarmonic(LowestPosition, HighestPosition, StartAngle,
                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "Modified sinusoidal":
            a = ModifiedSinusoidalSection(LowestPosition, HighestPosition,
                                          StartAngle, EndAngle, Precision,
                                          AngularVelocity)
        elif sectionType == "Trapezoidal":
            a = ModifiedTrapezoidalSection(LowestPosition, HighestPosition,
                                           StartAngle, EndAngle, Precision,
                                           AngularVelocity)
        elif sectionType == "Bezier":
            a = BezierSection(LowestPosition, HighestPosition,
                              StartAngle, EndAngle, Precision,
                              AngularVelocity)

        elif sectionType == "Dwell":
            a = StopSection(StartAngle, EndAngle, LowestPosition,
                            AngularVelocity, Precision)

        else:
            print("supported types: \n\nharmonic\ncicloidal\n5polynomial\n7polynomial\ndemiharmonic_Vi\ndemiharmonic_Vf")

        self.sections[section] = a

    def return_section_parameters(self, section):
        """returns a list with the paramaters of the specified section
        (being 0 the first section)
        Keyword Arguments:
        section -- (no default)
        """
        return (self.sections[section].LowestPosition,
                self.sections[section].HighestPosition,
                self.sections[section].StartAngle,
                self.sections[section].EndAngle,
                self.sections[section].Precision,
                self.sections[section].AngularVelocity)

    def del_cam_section(self, element):
        """Delete the cam section given the index of the element
        one wants to be remove

        Keyword Arguments:
        element -- 
        """
        del(self.sections[element])

    def del_all_cam_sections(self):
        """Deletes all cam sections
        
        """
        self.sections.clear()

    def number_of_sections(self):
        """return the number of sections
        
        """
        return len(self.sections)

    def CreatePositionPlot(self):
        """Creates the position plot but it does not display it
        
        """
        for section in self.sections:
            section.CreateYaxisPosition()
            pyplot.plot(section.abcissaeValues, section.ordinatePosition)

    def CreateVelocityPlot(self):
        """Creates the velocity plot but it does not display it
        
        """
        for section in self.sections:
            section.CreateYaxisVelocity()
            pyplot.plot(section.abcissaeValues, section.ordinateVelocity)

    def CreateAccelerationPlot(self):
        """Creates the velocity plot but it does not display it
        
        """
        for section in self.sections:
            section.CreateYaxisAcceleration()
            pyplot.plot(section.abcissaeValues, section.ordinateAcceleration)

    def CreateOverAccelerationPlot(self):
        """Creates the velocity plot but it does not display it
        
        """
        for section in self.sections:
            section.CreateYaxisOverAcceleration()
            pyplot.plot(section.abcissaeValues,
                        section.ordinateOverAcceleration)

    def ShowPlot(self):
        """Show the plot created
        
        """
        pyplot.show()

    def PlotPosition(self):
        """Creates and display the plot corresponding to the position
        
        """
        self.CreatePositionPlot()
        self.ShowPlot()

    def PlotVelocity(self):
        """Creates and displays the plot corresponding to the velocity
        
        """
        self.CreateVelocityPlot()
        self.ShowPlot()

    def PlotAcceleration(self):
        """Creates and displays the plot corresponding to the acceleration
        
        """
        self.CreateAccelerationPlot()
        self.ShowPlot()

    def PlotJerk(self):
        """Creates and displays the plot corresponding to the jerks
        """
        self.CreateOverAccelerationPlot()
        self.ShowPlot()

    def PlotEverything(self):
        """Creates and plots every single parameter of the cam object
        
        """
        self.CreatePositionPlot()
        self.CreateVelocityPlot()
        self.CreateAccelerationPlot()
        self.CreateOverAccelerationPlot()
        self.ShowPlot()

    def modify_section(self, LowestPosition, HighestPosition,
                       StartAngle, EndAngle,
                       positionSection, sectionType="harmonic",
                       AngularVelocity=1.0, Precision=0.1):
        """This method adds a CamSection to the list of sections

        Keyword Arguments:
        LowestPosition                    -- (default 0.0)
        HighestPosition                   -- (default 50.0)
        StartAngle       -- (default self.endPreviousAngle)
        EndAngle                          -- (default 200)
        Precision                         -- (default 0.1)
        AngularVelocity                   -- (default 20.0)
        """
        a = 0
        if sectionType == "harmonic":
            a = HarmonicSection(LowestPosition, HighestPosition, StartAngle,
                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "cicloidal":
            a = CicloidalSection(LowestPosition, HighestPosition, StartAngle,
                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "5polynomial":
            a = FifthDegreePolynomialSection(LowestPosition, HighestPosition, StartAngle,
                                             EndAngle, Precision, AngularVelocity)
        elif sectionType == "7polynomial":
            a = SeventhDegreePolynomialSection(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "demiharmonic_Vi":
            a = DemiHarmonicSectionZeroVinitial(LowestPosition, HighestPosition, StartAngle,
                                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "demiharmonic_Vf":
            a = DemiHarmonicSectionZeroVfinal(LowestPosition, HighestPosition, StartAngle,
                                              EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vf":
            a = DemiCicloidalSectionZeroVFinal(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vi":
            a = DemiCicloidalSectionZeroVInitial(LowestPosition, HighestPosition, StartAngle,
                                                 EndAngle, Precision, AngularVelocity)

        elif sectionType == "double_harmonic":
            a = DoubleHarmonic(LowestPosition, HighestPosition, StartAngle,
                               EndAngle, Precision, AngularVelocity)

        elif sectionType == "modified_trapezoidal":
            a = ModifiedTrapezoidalSection(LowestPosition, HighestPosition,
                                           StartAngle, EndAngle, Precision,
                                           AngularVelocity)
        elif sectionType == "bezier":
            a = BezierSection(LowestPosition, HighestPosition,
                              StartAngle, EndAngle, Precision,
                              AngularVelocity)

        elif sectionType == "stop":
            a = StopSection(StartAngle, EndAngle, LowestPosition)

        else:
            print("incorrect")
        
        self.sections[int(positionSection)] = a

    def set_section(self, LowestPosition, HighestPosition,
                    StartAngle, EndAngle,
                    positionSection, sectionType="harmonic",
                    AngularVelocity=1.0, Precision=0.1):
        """This method adds a CamSection to the list of sections

        Keyword Arguments:
        LowestPosition                    -- (default 0.0)
        HighestPosition                   -- (default 50.0)
        StartAngle       -- (default self.endPreviousAngle)
        EndAngle                          -- (default 200)
        Precision                         -- (default 0.1)
        AngularVelocity                   -- (default 20.0)
        """
        a = 0
        if sectionType == "harmonic":
            a = HarmonicSection(LowestPosition, HighestPosition, StartAngle,
                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "cicloidal":
            a = CicloidalSection(LowestPosition, HighestPosition, StartAngle,
                                 EndAngle, Precision, AngularVelocity)
        elif sectionType == "5polynomial":
            a = FifthDegreePolynomialSection(LowestPosition, HighestPosition,
                                             StartAngle,
                                             EndAngle, Precision,
                                             AngularVelocity)
        elif sectionType == "7polynomial":
            a = SeventhDegreePolynomialSection(LowestPosition, HighestPosition,
                                               StartAngle,
                                               EndAngle, Precision,
                                               AngularVelocity)
        elif sectionType == "demiharmonic_Vi":
            a = DemiHarmonicSectionZeroVinitial(LowestPosition, HighestPosition, StartAngle,
                                                EndAngle, Precision, AngularVelocity)
        elif sectionType == "demiharmonic_Vf":
            a = DemiHarmonicSectionZeroVfinal(LowestPosition, HighestPosition, StartAngle,
                                              EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vf":
            a = DemiCicloidalSectionZeroVFinal(LowestPosition, HighestPosition, StartAngle,
                                               EndAngle, Precision, AngularVelocity)
        elif sectionType == "demicicloidal_Vi":
            a = DemiCicloidalSectionZeroVInitial(LowestPosition, HighestPosition, StartAngle,
                                                 EndAngle, Precision, AngularVelocity)

        elif sectionType == "stop":
            a = StopSection(StartAngle, EndAngle,LowestPosition, angularVelocity)

        else:
            print("incorrect")

        self.sections.insert(positionSection, a)

    def generateCamOutline(self, followerType):
        """This method generates all the cam
        """
        self.followerType = followerType
        self.curvatureRadiusList = []
        self.curvatureRadiusPList = []
        self.pressureAngleList = []
        self.abcissaeValues = []
        self.offset = []
        outline = []
        if self.followerType == "punctual" or self.followerType == 0:
            # del(self.beta)
            # del(self.l1)
            # del(self.l2)
            # del(self.followerRadius)
            for section in self.sections:
                a, b, c = section.generateCam(self.rb,
                                              self.excentricity)
                for point, curvRadius, pressAngle in zip(a, b, c):
                    outline.append(point)
                    self.curvatureRadiusList.append(curvRadius)
                    self.pressureAngleList.append(pressAngle)
        elif self.followerType == "plane" or self.followerType == 1:
            # del(self.l1)
            # del(self.l2)
            # del(self.followerRadius)
            for section in self.sections:
                a, b = section.generate_cam_flat_follower(self.rb,
                                                          self.excentricity,
                                                          self.beta)
                c = section.abcissaeValues
                for point, curvRadius, abci in zip(a, b, c):
                    outline.append(point)
                    self.curvatureRadiusList.append(curvRadius)
                    self.pressureAngleList.append(self.beta)
                    self.abcissaeValues.append(abci)
        elif self.followerType == "circular" or self.followerType == 2:
            # del(self.l1)
            # del(self.l2)
            # del(self.beta)
            for section in self.sections:
                (a,
                 b,
                 c,
                 d,
                 e) = section.generate_cam_circular_follower(self.rb,
                                                             self.followerRadius,
                                                             self.excentricity)
                f = section.abcissaeValues
                for point, curvRadP, curvRadius, pressAngle, ofs ,abci in zip(a, b,
                                                                              c,
                                                                              d, e,
                                                                              f):
                    self.curvatureRadiusList.append(curvRadius)
                    self.curvatureRadiusPList.append(curvRadP)
                    self.pressureAngleList.append(pressAngle)
                    self.abcissaeValues.append(abci)
                    self.offset.append(ofs)
                    outline.append(point)
        elif self.followerType == "rotation_punctual" or self.followerType == 3:
            # del(self.beta)
            # del(self.excentricity)
            # del(self.followerRadius)
            for section in self.sections:
                for point in section.generate_cam_rotation_follower(self.rb,
                                                                    self.l1,
                                                                    self.l2):
                    outline.append(point)
        elif self.followerType == "rotation_plane" or self.followerType == 4:
            # del(self.beta)
            # del(self.excentricity)
            # del(self.followerRadius)
            self.angleGamma = math.degrees(math.asin((self.rb - self.l2) / self.l1))
            for section in self.sections:
                a, b = section.generate_cam_rotation_follower_plane(self.rb,
                                                                    self.l1,
                                                                    self.l2)
                c = section.abcissaeValues
                for point, curvRadius, abci in zip(a, b, c):
                    self.curvatureRadiusList.append(curvRadius)
                    self.pressureAngleList.append(0)
                    self.abcissaeValues.append(abci)
                    outline.append(point)
        elif self.followerType == "rotation_circular" or self.followerType == 5:
            # del(self.beta)
            # del(self.excentricity)
            numerator = (math.pow(self.l1, 2) +
                         math.pow(self.l2, 2) -
                         math.pow(self.rb + self.followerRadius, 2))
            denominator = 2 * self.l1 * self.l2
            # Fi2o is the initial angle the follower has because of the base
            # radius of the cam
            self.angleGamma = math.degrees(math.acos(numerator / denominator))
            for section in self.sections:
                a, b, c, d, e = section.generate_cam_rotation_follower_circular(self.rb,
                                                                                self.followerRadius,
                                                                                self.l1,
                                                                                self.l2)
                f = section.abcissaeValues
                for point, curvRadP, curvRadius, pressAngle, ofs, abci in zip(a,
                                                                              b,
                                                                              c,
                                                                              d,
                                                                              e,
                                                                              f):
                    self.curvatureRadiusPList.append(curvRadP)
                    self.curvatureRadiusList.append(curvRadius)
                    self.pressureAngleList.append(pressAngle)
                    self.offset.append(ofs)
                    outline.append(point)
                    self.abcissaeValues.append(abci)
        else:
            print("Error in generateCamOutline")
            exit(1)
                    
        unionPoint = outline[0]
        outline.append(unionPoint)
        # Debbuging
        # f = open("output.txt", 'w')
        # f.write(str(allPointList))
        # f.close()
        self.profile = outline
        return outline

    def makeDXF(self):
        """This method creates the dxf file"""
        drawing = dxf.drawing("cam.dxf")
        polyline = dxf.polyline()
        polyline.add_vertices(self.generateCamOutline(self.rb,
                                                      self.excentricity,
                                                      self.beta,
                                                      self.l1,
                                                      self.l2,
                                                      self.followerRadius,
                                                      self.followerType))
        drawing.add(polyline)
        drawing.save()

    def makeSVG(self):
        """This method creates the cam in svg"""
        svg = svgwrite.Drawing('test.svg')
        svg.add(svgwrite.shapes.Polygon(self.generateCam(self.rb)))
        svg.save()

    def drawSection(self, sectionNumber=0):
        
        drawing = dxf.drawing("cam.dxf")
        polyline = dxf.polyline()
        polyline.add_vertices(self.generateCamOutline_test(self.rb,
                                                           self.excentricity,
                                                           self.beta,
                                                           self.l1,
                                                           self.l2,
                                                           self.followerRadius,
                                                           self.followerType,
                                                           sectionNumber))
        drawing.add(polyline)
        drawing.save()

    def generateCamOutline_test(self, sectionNumber=0):
        """This method generates all the cam
        
        """
        if self.followerType == "punctual" or self.followerType == 0:
            # del(self.beta)
            # del(self.l1)
            # del(self.l2)
            # del(self.followerRadius)
            return self.sections[sectionNumber].generate_cam(self.rb, self.excentricity)
 
        elif self.followerType == "plane" or self.followerType == 1:
            # del(self.l1)
            # del(self.l2)
            # del(self.followerRadius)
            return self.sections[sectionNumber].generate_cam_flat_follower(self.rb,
                                                                           self.excentricity,
                                                                           self.beta)
        elif self.followerType == "circular" or self.followerType == 2:
            # del(self.l1)
            # del(self.l2)
            # del(self.beta)
            return self.sections[sectionNumber].generate_cam_circular_follower(self.rb,
                                                                               self.followerRadius,
                                                                               self.excentricity)
        elif self.followerType == "rotation_punctual" or self.followerType == 3:
            # del(self.beta)
            # del(self.excentricity)
            # del(self.followerRadius)
            return self.sections[sectionNumber].generate_cam_rotation_follower(self.rb,
                                                                               self.l1,
                                                                               self.l2)
        elif self.followerType == "rotation_plane" or self.followerType == 4:
            # del(self.beta)
            # del(self.excentricity)
            # del(self.followerRadius)
            return self.sections[sectionNumber].generate_cam_rotation_follower_plane(self.rb,
                                                                                     self.l1,
                                                                                     self.l2)
                    
        elif self.followerType == "rotation_circular" or self.followerType == 5:
            # del(self.beta)
            # del(self.excentricity)
            return self.sections[sectionNumber].generate_cam_rotation_follower_circular(self.rb,
                                                                                        self.followerRadius,
                                                                                        self.l1,
                                                                                        self.l2)
        else:
            print("error")

    def generateCamOutlineConjugate(self, followerType):
        """Returns 2 outlines that corresponds to the contact with
        two folllowers"""
        outline1 = []
        outline2 = []
        self.followerType = followerType
        self.radiusOfCurvatureListUp = []
        self.radiusOfCurvatureListLo = []
        self.radiusOfCurvaturePListUp = []
        self.radiusOfCurvaturePListLo = []
        self.pressureAngleListUp = []
        self.pressureAngleListLo = []
        self.abcissaeValues = []

        self.camOffset1 = []
        self.camOffset2 = []
        
        if self.followerType == "plane" or self.followerType == 0:
            # del(self.l1)
            # del(l2sup)
            # del(l2inf)
            # del(l3sup)
            # del(l3inf)
            # del(self.followerRadius)
            for section in self.sections:
                sinBeta = math.sin(math.radians(self.beta))
                cosBeta = math.cos(math.radians(self.beta))
                initDistance = (self.rb + (self.excentricity * sinBeta)) / cosBeta
                self.rb2 = self.separation - initDistance
                a, b, c, d = section.Conjugate_plain(self.rb,
                                                     self.beta,
                                                     self.excentricity,
                                                     self.separation)
                e = section.abcissaeValues
                for out1, out2, cRad1, cRad2, abci in zip(a, b, c, d, e):
                    outline1.append(out1)
                    outline2.append(out2)
                    self.radiusOfCurvatureListUp.append(cRad1)
                    self.radiusOfCurvatureListLo.append(cRad2)
                    self.pressureAngleListUp.append(self.beta)
                    self.pressureAngleListLo.append(self.beta)
                    self.abcissaeValues.append(abci)
            return outline1, outline2
        elif self.followerType == "circular" or self.followerType == 1:
            initDistance = math.sqrt(math.pow((self.rb +
                                               self.followerRadius), 2) -
                                     math.pow(self.excentricity, 2))
            self.rb2 = self.separation - initDistance
            for section in self.sections:
                (a,
                 b,
                 c,
                 d,
                 e,
                 f,
                 g,
                 h,
                 i,
                 j) = section.Conjugate_circular(self.rb,
                                                 self.followerRadius,
                                                 self.excentricity,
                                                 self.separation)
                k = section.abcissaeValues
                for out1, out2, cRp1, cRp2, cRad1, cRad2, pA1, pA2, of1, of2, abci in zip(a,
                                                                                         b,
                                                                                         c,
                                                                                         d,
                                                                                         e,
                                                                                         f,
                                                                                         g,
                                                                                         h,
                                                                                         i,
                                                                                         j,
                                                                                         k):
                    outline1.append(out1)
                    outline2.append(out2)
                    self.radiusOfCurvaturePListUp.append(cRp1)
                    self.radiusOfCurvaturePListLo.append(cRp2)
                    self.radiusOfCurvatureListUp.append(cRad1)
                    self.radiusOfCurvatureListLo.append(cRad2)
                    self.pressureAngleListUp.append(pA1)
                    self.pressureAngleListLo.append(pA2)
                    self.abcissaeValues.append(abci)
                    self.camOffset1.append(of1)
                    self.camOffset2.append(of2)
            return outline1, outline2
        elif self.followerType == "angular_plane" or self.followerType == 2:
            # del(self.followerRadius)
            # del(self.separation)
            # del(l3sup)
            # del(l3inf)
            gamma1r = math.asin((self.rb) / self.l1)
            self.gamma1 = math.degrees(gamma1r)
            self.gamma2 = self.gamma1 - self.beta
            gamma2r = math.radians(self.gamma2)
            self.rb2 = math.sin(gamma2r) * self.l1
            for section in self.sections:
                a, b, c, d = section.Conjugate_angular_plane(self.rb,
                                                             self.beta,
                                                             self.l1,
                                                             0,
                                                             0)
                e = section.abcissaeValues
                for out1, out2, cRad1, cRad2, abci in zip(a, b, c, d, e):
                    outline1.append(out1)
                    outline2.append(out2)
                    self.radiusOfCurvatureListUp.append(cRad1)
                    self.radiusOfCurvatureListLo.append(cRad2)
                    self.pressureAngleListUp.append(0)
                    self.pressureAngleListLo.append(0)
                    self.abcissaeValues.append(abci)
            return outline1, outline2
        elif self.followerType == "angular_circular" or self.followerType == 3:
            # del(self.separation)
            # del(l2sup)
            # del(l2inf)
            numerator = (math.pow(self.l1, 2) +
                         math.pow(self.l3sup, 2) -
                         math.pow(self.rb + self.followerRadius, 2))
            denominator = 2 * self.l1 * self.l3sup
            # Fi2o is the initial angle the follower has because of the base
            # radius of the cam
            gamma1r = math.acos(numerator / denominator)
            self.gamma1 = math.degrees(gamma1r)
            self.gamma2 = self.beta - self.gamma1
            gamma2r = math.radians(self.gamma2)
            self.rb2 = math.sqrt(math.pow(self.l1, 2) +
                                 math.pow(self.l3inf, 2) -
                                 (denominator * gamma2r)) - self.followerRadius
            for section in self.sections:
                (a,
                 b,
                 c,
                 d,
                 e,
                 f,
                 g,
                 h,
                 i,
                 j) = section.Conjugate_angular_circular(self.rb,
                                                         self.followerRadius,
                                                         self.l1,
                                                         self.l3sup,
                                                         self.l3inf,
                                                         self.beta)
                k = section.abcissaeValues
                for out1, out2, cRp1, cRp2, cRad1, cRad2, pA1, pA2, of1, of2, abci in zip(a,
                                                                                          b,
                                                                                          c,
                                                                                          d,
                                                                                          e,
                                                                                          f,
                                                                                          g,
                                                                                          h,
                                                                                          i,
                                                                                          j,
                                                                                          k):
                    outline1.append(out1)
                    outline2.append(out2)
                    self.radiusOfCurvaturePListUp.append(cRp1)
                    self.radiusOfCurvaturePListLo.append(cRp2)
                    self.radiusOfCurvatureListUp.append(cRad1)
                    self.radiusOfCurvatureListLo.append(cRad2)
                    self.pressureAngleListUp.append(pA1)
                    self.pressureAngleListLo.append(pA2)
                    self.camOffset1.append(of1)
                    self.camOffset2.append(of2)
                    self.abcissaeValues.append(abci)
            return outline1, outline2
        else:
            print("no follower selected")
            exit(1)

    def makeDXF_d(self, l2sup, l2inf, l3sup,
                  l3inf, same=True):
        """This method creates the dxf file"""
        print(self.followerType)
        polyline = dxf.polyline()
        polyline2 = dxf.polyline()
        outline1, outline2 = self.generateCamOutlineConjugate(self.rb,
                                                              self.excentricity,
                                                              self.beta,
                                                              self.separation,
                                                              self.l1,
                                                              l2sup,
                                                              l2inf,
                                                              l3sup,
                                                              l3inf,
                                                              self.followerRadius,
                                                              self.followerType)
        if same:
            drawing = dxf.drawing("cam.dxf")
            polyline.add_vertices(outline1)
            polyline2.add_vertices(outline2)
            drawing.add(polyline)
            drawing.add(polyline2)
            drawing.save()
        else:
            drawing1 = dxf.drawing("cam1.dxf")
            drawing2 = dxf.drawing("cam2.dxf")
            polyline.add_vertices(outline1)
            polyline2.add_vertices(outline2)
            drawing1.add(polyline)
            drawing2.add(polyline2)
            drawing1.save()
            drawing2.save()

    def GenerateDesmoPlain(self):
        """
        
        """
        self.abcissaeValues = []
        self.curvatureRadiusList = []
        self.pressureAngleList = []
        outline1 = []
        shouldIGenerate = True
        highestPosition = 0
        for section in self.sections:
            if section.EndAngle > 180:
                if section.StartAngle > 180:
                    print("Nono adecuate section")
                    shouldIGenerate = False
                else:
                    section.EndAngle = 180
                    section.ReCalculateAbcissaeValues()
            else:  # Normal procedure
                pass

            if shouldIGenerate:
                prof, cRad = section.generate_cam_flat_follower(self.rb,
                                                                self.excentricity,
                                                                self.beta)
                highestPostionAux = max(section.HighestPosition,
                                        section.LowestPosition)
                if highestPostionAux > highestPosition:
                    highestPosition = highestPostionAux
                else:
                    pass
                
                abc = section.abcissaeValues
                for point, rCurv, abci in zip(prof, cRad, abc):
                    outline1.append(point)
                    self.curvatureRadiusList.append(rCurv)
                    self.pressureAngleList.append(self.beta)
                    self.abcissaeValues.append(abci)
            else:
                print("section not processed")

        initDistance = ((self.rb + (self.excentricity * math.sin(math.radians(self.beta)))) /
                        math.cos(math.radians(self.beta)))
        self.separation = initDistance + initDistance + highestPosition
        print(self.separation)
        # time of calculate the anti part
        shouldIGenerate = True
        for section in self.sections:
            if section.EndAngle > 180:
                if section.StartAngle > 180:
                    print("Nono adecuate section")
                    shouldIGenerate = False
                else:
                    section.EndAngle = 180
                    section.ReCalculateAbcissaeValues()
            else:  # Normal procedure
                pass

            if shouldIGenerate:
                prof, Rad = section.GeneratePlainAnti(self.rb,
                                                      self.beta,
                                                      self.excentricity,
                                                      self.separation)
                for point, rCurv, abci in zip(prof, Rad,
                                              self.abcissaeValues):
                    outline1.append(point)
                    self.curvatureRadiusList.append(rCurv)
                    self.pressureAngleList.append(self.beta)
                    self.abcissaeValues.append(abci + 180)
            else:
                print("Section not processed")

        return outline1

    def makeDXF_c(self, l2sup, l2inf):
        """This method creates the dxf file"""
        print(self.followerType)
        drawing = dxf.drawing("cam.dxf")
        polyline = dxf.polyline()
        polyline.add_vertices(self.generateCamOutlineConstWidth(self.rb,
                                                                self.excentricity,
                                                                self.beta,
                                                                self.l1,
                                                                l2sup,
                                                                l2inf,
                                                                self.followerRadius,
                                                                self.followerType))
        drawing.add(polyline)
        drawing.save()

    def generateCamOutlineConstWidth(self,
                                     l2sup,
                                     l2inf):
        """Returns an outlines that corresponds to the contact with
        two folllowers"""
        if self.followerType == "plane" or self.followerType == 0:
            del(self.followerRadius)
            return self.GenerateDesmoPlain(self.rb,
                                           self.beta,
                                           self.excentricity)
        elif self.followerType == "circular" or self.followerType == 1:
            return self.GenerateDesmoCircular(self.rb,
                                              self.followerRadius,
                                              self.excentricity)
        elif self.followerType == "angular_plane" or self.followerType == 2:
            return self.GenerateDesmoOscillatingPlane(self.rb,
                                                      self.l1,
                                                      l2sup,
                                                      l2inf)
        else:
            print("no follower selected")
            exit(1)

    def GenerateDesmoCircular(self):
        """
        
        """
        outline1 = []
        outlineAnti = []
        shouldIGenerate = True
        maxRad = 0
        for section in self.sections:
            if section.EndAngle > 180:
                if section.StartAngle > 180:
                    print("Nono adecuate section")
                    shouldIGenerate = False
                else:
                    section.EndAngle = 180
                    section.ReCalculateAbcissaeValues()
            else:  # Normal procedure
                pass

            if shouldIGenerate:
                outline = section.generate_cam_circular_follower(self.rb,
                                                                 self.followerRadius,
                                                                 self.excentricity)
                for point in outline:
                    outline1.append(point)
            else:
                print("section not processed")

            x, y = outline1[0]
            minRad = math.hypot(y, x)
        for x, y in outline1:
            if maxRad < math.hypot(x, y):
                maxRad = math.hypot(x, y)
            elif minRad > math.hypot(x, y):
                minRad = math.hypot(x, y)
            else:
                pass

        self.separation = maxRad + minRad
        # self.separation = ((self.separation * math.cos(math.radians(self.beta))) -
        #               (2 * self.excentricity * math.sin(math.radians(self.beta))))
        # time of calculate the anti part
        shouldIGenerate = True
        for section in self.sections:
            if section.EndAngle > 180:
                if section.StartAngle > 180:
                    print("Nono adecuate section")
                    shouldIGenerate = False
                else:
                    section.EndAngle = 180
                    section.ReCalculateAbcissaeValues()
            else:  # Normal procedure
                pass

            if shouldIGenerate:
                outlineAnti = section.GenerateCircularAnti(self.rb,
                                                           self.excentricity,
                                                           self.followerRadius,
                                                           self.separation)
                for point in outlineAnti:
                    outline1.append(point)
                    
            else:
                print("Section not processed")

        return outline1

    def getProfile(self):
        return self.profile

    def clearProfile(self):
        self.profile = []

    # def GenerateDesmoOscillatingPlane(self, rb2, self.l1, l2sup, l2inf):
    #     """
        
    #     """
    #     outline1 = []
    #     outlineAnti = []
    #     shouldIGenerate = True
    #     maxRad = 0
    #     sPhi0 = math.radians(self.sections[0].StartAngle)
    #     c = (l2inf - l2sup) / self.l1
    #     sinPhi0 = math.sin(sPhi0)
    #     maxAngle = sPhi0 - math.asin(c - sinPhi0) + math.pi
    #     self.rb = (l2sup + l2inf -
    #           math.sin(math.radians(self.sections[0].EndAngle))) / 2
    #     print(math.degrees(maxAngle))
    #     for section in self.sections:
    #         if section.EndAngle > math.degrees(maxAngle):
    #             if section.StartAngle > math.degrees(maxAngle):
    #                 print("Nono adecuate section")
    #                 shouldIGenerate = False
    #             else:
    #                 section.EndAngle = math.degrees(maxAngle)
    #                 section.ReCalculateAbcissaeValues()
    #         else:  # Normal procedure
    #             pass

    #         if shouldIGenerate:
    #             outline = section.generate_cam_rotation_follower_plane(self.rb,
    #                                                                    self.l1,
    #                                                                    l2sup)
    #             for point in outline:
    #                 outline1.append(point)
    #         else:
    #             print("section not processed")

    #         x, y = outline1[0]
    #         minRad = math.hypot(y, x)
    #     for x, y in outline1:
    #         if maxRad < math.hypot(x, y):
    #             maxRad = math.hypot(x, y)
    #         elif minRad > math.hypot(x, y):
    #             minRad = math.hypot(x, y)
    #         else:
    #             pass
    #     l2inf = maxRad - l2sup
    #     # self.separation = ((self.separation * math.cos(math.radians(self.beta))) -
    #     #               (2 * self.excentricity * math.sin(math.radians(self.beta))))
    #     # time of calculate the anti part
    #     shouldIGenerate = True
    #     for section in self.sections:
    #         if section.EndAngle > math.degrees(maxAngle):
    #             if section.StartAngle > math.degrees(maxAngle):
    #                 print("Nono adecuate section")
    #                 shouldIGenerate = False
    #             else:
    #                 section.EndAngle = math.degrees(maxAngle)
    #                 section.ReCalculateAbcissaeValues()
    #         else:  # Normal procedure
    #             pass

    #         if shouldIGenerate:
    #             outlineAnti = section.GenerateOscilatingPlaneAnti(self.rb,
    #                                                               self.l1,
    #                                                               l2sup,
    #                                                               l2inf,
    #                                                               c)
    #             for point in outlineAnti:
    #                 outline1.append(point)
                    
    #         else:
    #             print("Section not processed")

    #     return outline1
    def maxDisplacement(self):
        """Returns the maximum displacement
        value of the law
        """
        maxCandidate = []
        for section in self.sections:
            maxCandidate.append(max(section.ordinatePosition))
        return max(maxCandidate)

    def minDisplacement(self):
        """Returns the minimum displacement
        value of the law
        """
        minCandidate = []
        for section in self.sections:
            minCandidate.append(min(section.ordinatePosition))
        return min(minCandidate)

    def maxVelocity(self):
        """Returns the maximum velocity
        value of the law
        """
        maxCandidate = []
        for section in self.sections:
            maxCandidate.append(max(section.ordinateVelocity))
        return max(maxCandidate)

    def minVelocity(self):
        """Returns the minimum displacement
        value of the law
        """
        minCandidate = []
        for section in self.sections:
            minCandidate.append(min(section.ordinateVelocity))
        return min(minCandidate)

    def maxAcceleration(self):
        """Returns the maximum acceleration
        value of the law
        """
        maxCandidate = []
        for section in self.sections:
            maxCandidate.append(max(section.ordinateAcceleration))
        return max(maxCandidate)

    def minAcceleration(self):
        """Returns the minimum acceleration
        value of the law
        """
        minCandidate = []
        for section in self.sections:
            minCandidate.append(min(section.ordinateAcceleration))
        return min(minCandidate)

    def maxJerk(self):
        """Returns the maximum jerk
        value of the law
        """
        maxCandidate = []
        for section in self.sections:
            maxCandidate.append(max(section.ordinateOverAcceleration))
        return max(maxCandidate)

    def minJerk(self):
        """Returns the minimum jerk
        value of the law
        """
        minCandidate = []
        for section in self.sections:
            minCandidate.append(min(section.ordinateOverAcceleration))
        return min(minCandidate)

    def maxPressureAngle(self):
        """Returns the maximum value
        of the pressure angle
        """
        return max(self.pressureAngleList)

    def minPressureAngle(self):
        """Returns the minimum value
        of the pressure angle
        """
        return min(self.pressureAngleList)

    def maxCurvatureRadius(self):
        """Returns the maxmimum value of the
        radius of curvature
        """
        return max(self.curvatureRadiusList)

    def minCurvatureRadius(self):
        """Returns the minimum value of the
        radius of curvature
        """
        return min(self.curvatureRadiusList)

    def maxPressureAngleConjugate1(self):
        """Returns the maximum value
        of the pressure angle
        """
        return max(self.pressureAngleListUp)

    def minPressureAngleConjugate1(self):
        """Returns the minimum value
        of the pressure angle
        """
        return min(self.pressureAngleListUp)

    def maxCurvatureRadiusConjugate1(self):
        """Returns the maxmimum value of the
        radius of curvature
        """
        return max(self.radiusOfCurvatureListUp)

    def minCurvatureRadiusConjugate1(self):
        """Returns the minimum value of the
        radius of curvature
        """
        return min(self.radiusOfCurvatureListUp)

    def maxPressureAngleConjugate2(self):
        """Returns the maximum value
        of the pressure angle
        """
        return max(self.pressureAngleListLo)

    def minPressureAngleConjugate2(self):
        """Returns the minimum value
        of the pressure angle
        """
        return min(self.pressureAngleListLo)

    def maxCurvatureRadiusConjugate2(self):
        """Returns the maxmimum value of the
        radius of curvature
        """
        return max(self.radiusOfCurvatureListLo)

    def minCurvatureRadiusConjugate2(self):
        """Returns the minimum value of the
        radius of curvature
        """
        return min(self.radiusOfCurvatureListLo)

    def isDisplacementContinuum(self):
        """Returns true if the displacement is
        a continuum function
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinatePosition[1]
            end = section.ordinatePosition[-1]
            listOfIniEnd.append([ini, end])

        return checkContinuity(listOfIniEnd, 0.2)

    def isVelocityContinuum(self):
        """Returns true if the velocity
        function is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateVelocity[1]
            end = section.ordinateVelocity[-1]
            listOfIniEnd.append([ini, end])

        return checkContinuity(listOfIniEnd, 0.2)
        
    def isAccelerationContinuum(self):
        """Returns True if the acceleration
        function is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateAcceleration[1]
            end = section.ordinateAcceleration[-1]
            listOfIniEnd.append([ini, end])

        return checkContinuity(listOfIniEnd, 0.5)

    def isJerkContinuum(self):
        """Returns True if the jerk function
        is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateOverAcceleration[1]
            end = section.ordinateOverAcceleration[-1]
            listOfIniEnd.append([ini, end])

        return checkContinuity(listOfIniEnd, 5)

    def createSecondHalf(self):
        """This creates another half for the constant width
        """
        start = self.sections[-1].EndAngle
        self.restAbci = np.arange(start, 360, self.precision)
        self.orDisplacement = []
        self.orVelocity = []
        self.orAcceleration = []
        self.orJerk = []
        # list4FindingMax = []
        # initDistance = ((self.rb +
        #                  (self.excentricity *
        #                   math.sin(math.radians(self.beta)))) /
        #                 math.cos(math.radians(self.beta)))
        
        # for section in self.sections:
        #     list4FindingMax.append(max(section.ordinatePosition))

        # maxPosition = max(list4FindingMax)

        maximum = self.maxDisplacement()
        for section in self.sections:
            for a, b, c, d, e in zip(section.ordinatePosition,
                                     section.ordinateVelocity,
                                     section.ordinateAcceleration,
                                     section.ordinateOverAcceleration,
                                     section.abcissaeValues):
                self.orDisplacement.append(maximum - a)
                self.orVelocity.append(-b)
                self.orAcceleration.append(-c)
                self.orJerk.append(-d)
                # self.abcissaeValues.append(e + 180)

    def returnOtherHalfParam(self):
        """Returns the values obtained in the second half
        
        """
        return (self.restAbci, self.orDisplacement, self.orVelocity, self.orAcceleration, self.orJerk)

    def isDisplacementContinuumCW(self):
        """Returns true if the displacement is
        a continuum function
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinatePosition[0]
            end = section.ordinatePosition[-1]
            listOfIniEnd.append([ini, end])
        ini = self.orDisplacement[0]
        end = self.orDisplacement[-1]
        listOfIniEnd.append([ini, end])

        return checkContinuity(listOfIniEnd, 0.2)

    def isVelocityContinuumCW(self):
        """Returns true if the velocity
        function is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateVelocity[0]
            end = section.ordinateVelocity[-1]
            listOfIniEnd.append([ini, end])
        ini = self.orVelocity[0]
        end = self.orVelocity[-1]
        listOfIniEnd.append([ini, end])
        
        return checkContinuity(listOfIniEnd, 0.2)
        
    def isAccelerationContinuumCW(self):
        """Returns True if the acceleration
        function is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateAcceleration[0]
            end = section.ordinateAcceleration[-1]
            listOfIniEnd.append([ini, end])
        ini = self.orAcceleration[0]
        end = self.orAcceleration[-1]
        listOfIniEnd.append([ini, end])
        return checkContinuity(listOfIniEnd, 0.2)

    def isJerkContinuumCW(self):
        """Returns True if the jerk function
        is continuum
        """
        listOfIniEnd = []
        for section in self.sections:
            ini = section.ordinateOverAcceleration[0]
            end = section.ordinateOverAcceleration[-1]
            listOfIniEnd.append([ini, end])
        ini = self.orJerk[0]
        end = self.orJerk[-1]
        listOfIniEnd.append([ini, end])
        print(listOfIniEnd)
        print("here")
        return checkContinuity(listOfIniEnd, 100)
